//
//  FileFinder.m
//  FileFinder
//
//  Created by hoolai on 2018/11/19.
//  Copyright © 2018年 hoolai. All rights reserved.
//
//  Updated by wenyushu on 2018/11/20.
//  1. 将输出到log.plist文件改用NSDictionary和NSMutableArray写入 而不是之前的文本文件
//  2. 修改了一些不规范的命名

#import "FileFinder.h"
/* review
 初始化:
 initWithSourcePath:(NSString *)source TargetPath:(NSString *)target 应该作为其他初始化方法调用的终点, 也就是 init 方法里面, 应该是 return [self initWithSourcePath:nil TargetPath:nil]. 这样, 保证所有的逻辑都能在 initWithSourcePath:(NSString *)source TargetPath:(NSString *)target 中进行处理. 而在整个方法里面, 应该对于传进来的参数进行检查, 如果source, target 为nil. self = nil, 并直接返回 self. 表示初始化失败.
 注释:
 注释的作用应该是帮助理解. 而程序源文件如果命名规范, 函数和变量名本身就应该起到引导思路的作用. 无效的注释反而影响阅读.
 */

@interface FileFinder()
//review: 去查一下 NSDictionary 和 plist 文件. 现在 listhandle 是写成为一个文本文件.
// review: 成员变量和方法之间空行
@property (strong,nonatomic) NSFileManager *manager;
@property (strong,nonatomic) NSMutableArray *filesInfo;

//- (NSArray *)findAllFileFromPath:(NSString *)path;
//- (NSMutableArray *)selectFilesEndWithHorMFromList:(NSArray *)fileList Path:(NSString *)path;
// review: OC 不像 C++, 函数必须先声明后实现, 这两个私有函数可以不写上面的声明式.
@end

@implementation FileFinder

- (instancetype)init
{
    self = [self initWithSourcePath:nil TargetPath:nil];
    return self;
}

- (instancetype)initWithSourcePath:(nullable NSString *)source TargetPath:(nullable NSString *)target{
    if(source==nil || target==nil){
        self = nil;
        return self;
    }
    self = [super init];
    self.manager = [NSFileManager defaultManager];
    self.sourcePath=source;
    self.targetPath=target;
    /*
     关于NSFileHandle的部分 删除改用NSMutableDictionary
     NSString *filePath = [NSString stringWithFormat:@"%@/log.plist",target];
    [self.manager createFileAtPath:filePath contents:nil attributes:nil];
    NSFileHandle *outlist = [NSFileHandle fileHandleForWritingAtPath:filePath];
    [self setListhandle:outlist];
     */
    self.filesInfo = [NSMutableArray array];
    NSString *filePath = [NSString stringWithFormat:@"%@/log.plist",target];
    [self.manager createFileAtPath:filePath contents:nil attributes:nil];
    return self;
}
/*
- (BOOL)addSourcePath:(NSString *)source{
    if([self.manager fileExistsAtPath:source isDirectory:YES]){
        self.sourcePath = source;
        return YES;
    }
    return NO;
}

- (BOOL)addTargetPath:(NSString *)target{
    if([self.manager fileExistsAtPath:target isDirectory:YES]){
        self.targetPath = target;
        return YES;
    }
    return NO;
}
 */

/* review
 运算符两边加空格. 当在判断表达式里面, 为了表达判断单元紧密, 可以不加.
 但不管加不加, 下面的代码格式没有统一.
 命名有问题, 这个函数返回的是该路径下的子文件, 并不是 all. 改为 filesInPath, 以动词开头的函数, 表示这是一个动作, 不能体现这个函数的作用在于返回值.
 */
- (NSArray *)getFilesInPath:(NSString *)path{
    //NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
    NSError *err = nil;
    NSArray *fileList = [[NSArray alloc] init];
    fileList = [self.manager contentsOfDirectoryAtPath:path error:&err];
    //NSLog(@"find file - path : %@",path);
    //NSLog(@"filelist - %@",fileList.lastObject);
    return fileList;
}

- (NSMutableArray *)selectFilesEndWithHorMFromList:(NSArray *)fileList Path:(NSString *)path{
    //将文件分类为以.m .h结尾的文件和文件夹 （其他丢弃）
    NSMutableArray *selectedFilesList = [NSMutableArray array];
    NSMutableArray *directories = [NSMutableArray array];
    for(NSString *f in fileList){
        NSString *file = [NSString stringWithFormat:@"%@/%@",path,f];
        BOOL isDir = NO;
        [self.manager fileExistsAtPath:file isDirectory:&isDir]; // review: unused variable.
//        if(res)NSLog(@"res is YES");
//        else NSLog(@"res is NO");
//        if(isDir)NSLog(@"isDir is YES");
//        else NSLog(@"isDir is NO");
        if(isDir){
            [directories addObject:file];
        }else if([[f pathExtension] isEqualToString:@"m"]||[[f pathExtension] isEqualToString:@"h"]){
            [selectedFilesList addObject:f];
        }else{// review: else 后面的 {}
            //不以.m .h结尾的其他文件 直接丢弃不管
        }
    }
    //NSLog(@"select file - path: %@/%@",path,fileList.lastObject);
    //NSLog(@"dir file - path: %@",directories.lastObject);
    //NSLog(@"selected filelist: %@",selectedFilesList.lastObject);
    [self copyFileFromList:selectedFilesList toTarget:path];
        
    for(NSString *dir in directories){
        //NSString *newPath=[NSString stringWithFormat:@"%@/%@",path,dir];
        //DFS递归调用  进入子文件夹继续查找并筛选
        [self selectFilesEndWithHorMFromList:[self getFilesInPath:dir] Path:dir];
        //[self selectFilesEndWithHorMFromList:[self findAllFileFromPath:newPath] Path:newPath];
    }
    
    
    return selectedFilesList;
}

// review: copyFileFromList:(NSMutableArray *)fileList toTarget:(NSString *)path.
- (void)copyFileFromList:(NSMutableArray *)fileList toTarget:(NSString *)path{
    if(fileList.count==0)
        return;
    //NSLog(@"copy file - path : %@",fileList.firstObject);
    //将源路径转化为目标路径
    NSMutableString *targetPath = [NSMutableString stringWithString:path];
    [targetPath replaceOccurrencesOfString:self.sourcePath
                                withString:self.targetPath
                                   options:NSAnchoredSearch
                                     range:NSMakeRange(0, targetPath.length)];
    for(NSString * f in fileList){
        
        //NSLog(@"source path %@",self.sourcePath);
        //NSLog(@"target path %@",self.targetPath);
        //NSLog(@"targetpath - path:%@",targetPath);
        NSError *err;
        if(![self.manager createDirectoryAtPath:targetPath withIntermediateDirectories:YES attributes:nil error:&err]){
            NSLog(@"%@ created error:%@",targetPath,err);
            return;
        }
        //打开源文件
        NSString *inFileName = [NSString stringWithFormat:@"%@/%@",path,f];
        NSFileHandle *inFile = [NSFileHandle fileHandleForReadingAtPath:inFileName];
        if(inFile == nil){
            NSLog(@"open infile failed");
            return;
        }
        
        //创建输出文件
        NSString *outFileName = [NSString stringWithFormat:@"%@/%@",targetPath,f];
        [self.manager createFileAtPath:outFileName contents:nil attributes:nil];
        NSFileHandle *outFile = [NSFileHandle fileHandleForWritingAtPath:outFileName];
        if(outFile == nil){
            NSLog(@"open outfile failed");
            return;
        }
        //输出文件可能包含数据，截断输出文件
        [outFile truncateFileAtOffset:0];
        //从inFile中读取，再写入到outFile
        NSData *buffer = [inFile readDataToEndOfFile];
        NSString *content = [[NSString alloc]initWithData:buffer encoding:NSUTF8StringEncoding];
        NSArray *str = [content componentsSeparatedByString:@"\n"];
        NSInteger count = str.count;
        
        //[self.listhandle seekToEndOfFile];
//        NSMutableString *filename = [NSMutableString stringWithString:path];
//        [filename replaceOccurrencesOfString:self.sourcePath
//                                  withString:@""
//                                     options:NSAnchoredSearch
//                                       range:NSMakeRange(0, filename.length)];
        //[self.listhandle writeData:[[NSString stringWithFormat:@"文件名：%@\n代码行数：%ld  ",f,count]dataUsingEncoding:NSUTF8StringEncoding]];
        /*
         Update: 删除了上面的关于listhandle的操作 改为使用Dictionary
         将count值传入写文件的方法中一起处理
         */
        [self writeFileInfoFromPath:inFileName count:count];
        [outFile writeData:buffer];//将读入的文件内容写入到新的文件 完成复制。
        
    }
}

- (void)writeFileInfoFromPath:(NSString *)path count:(NSInteger)count{
    NSError *err;
    NSDictionary *fileAttributes = [self.manager attributesOfItemAtPath:path error:&err];
    if(fileAttributes){
        NSNumber *fileSize;
        NSDate *creationDate, *modificationDate;
        //获取文件大小
        fileSize = [fileAttributes objectForKey:NSFileSize];
        //获取文件创建时间
        creationDate = [fileAttributes objectForKey:NSFileCreationDate];
        //获取文件修改时间
        modificationDate = [fileAttributes objectForKey:NSFileModificationDate];
        //获得的时间由于时区的缘故和北京时间相差8小时 需要转成当地时间
        NSTimeZone *zone = [NSTimeZone systemTimeZone];
        NSInteger interval = [zone secondsFromGMTForDate:[NSDate date]];
        creationDate = [creationDate dateByAddingTimeInterval: interval];
        modificationDate = [modificationDate dateByAddingTimeInterval:interval];
        //[self.listhandle writeData:[[NSString stringWithFormat:@"创建日期：%@  修改日期：%@  文件大小：%@字节\n",creationDate,modificationDate,fileSize]dataUsingEncoding:NSUTF8StringEncoding]];
        //Update: 改为使用NSDictionary存储数据，添加到NSMutableArray中，最后再写入
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[path lastPathComponent],@"文件名",fileSize,@"文件大小",creationDate,@"创建时间",modificationDate,@"修改时间",[NSString stringWithFormat:@"%li",count],@"代码行数", nil];
        [self.filesInfo addObject:dict];
        
        //NSArray *arr1 = [NSArray arrayWithObjects:[path lastPathComponent],  fileSize,creationDate,modificationDate,[NSString stringWithFormat:@"%li",count],nil];
        //NSArray *arr2 = [NSArray arrayWithObjects:@"文件名",@"文件大小",@"创建时间",@"修改时间",@"代码行数",nil];
        //[self.dictionary setObject:arr1 forKey:arr2];
        //NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:self.dictionary format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
        //[plistData writeToFile:[NSString stringWithFormat:@"%@/log.plist",self.targetPath] atomically:YES];
        //[self.dictionary writeToFile:[NSString stringWithFormat:@"%@/log.plist",self.targetPath] atomically:YES];
    }
}
- (void)copyStart{
    [self selectFilesEndWithHorMFromList:[self getFilesInPath:self.sourcePath] Path:self.sourcePath];
    //Update: 将全部信息添加到filesInfo中再一次全部写入
    [self.filesInfo writeToFile:[NSString stringWithFormat:@"%@/log.plist",self.targetPath] atomically:YES];
}
@end
